package com.zjc.app.api.sdk.client;

import com.google.gson.reflect.TypeToken;
import com.zjc.app.api.sdk.Constants.Constants;
import com.zjc.app.api.sdk.dto.ResultDto;
import com.zjc.app.api.sdk.dto.request.ApiBizFarmDeviceBindDTO;
import com.zjc.app.api.sdk.dto.request.ApiBizFarmDeviceDto;
import com.zjc.app.api.sdk.dto.request.ApiFarmDeviceMqttInstructionSendDTO;
import com.zjc.app.api.sdk.dto.request.ApiQueryBizFarmProductDto;
import com.zjc.app.api.sdk.dto.request.FarmDevicePropertiesReqDTO;
import com.zjc.app.api.sdk.dto.request.NjkQueryDevicePositionsReqDto;
import com.zjc.app.api.sdk.dto.result.ApiBizFarmProductDto;
import com.zjc.app.api.sdk.dto.result.DevicePropertiesDTO;
import com.zjc.app.api.sdk.dto.result.NjkPositionResult;
import com.zjc.app.api.sdk.dto.result.NjkPositionResultDTO;
import com.zjc.app.api.sdk.dto.result.NjkResult;
import com.zjc.app.api.sdk.dto.result.NjkResultDTO;
import com.zjc.app.api.sdk.dto.result.ProductPropertyWithValueResultListDTO;
import com.zjc.app.api.sdk.exception.AppBizRuntimeException;
import com.zjc.app.api.sdk.utils.WebUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class FarmDeviceClient extends BaseClient {

    public FarmDeviceClient(String serverUrl, String appId, String appSecret, Integer connectTimeout, Integer readTimeout) {
        super(serverUrl, appId, appSecret, connectTimeout, readTimeout);
    }

    /**
     * 获取设备二次应答结果
     *
     * @param request
     * @return
     * @throws IOException
     * @throws AppBizRuntimeException
     */
    public ResultDto<String> farmDeviceMqttInstructionSend(ApiFarmDeviceMqttInstructionSendDTO request) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDeviceMqttInstruction.send";
        return super.doPost(url, request, new TypeToken<ResultDto<String>>() {
        });
    }

    /**
     * 获取设备最新属性
     *
     * @param uniqueNo
     * @return
     * @throws IOException
     * @throws AppBizRuntimeException
     */
    public ResultDto<List<ProductPropertyWithValueResultListDTO>> getFarmDeviceProperties(String uniqueNo) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDeviceProperties.get";
        Map<String, String> params = new TreeMap<>();
        params.put("uniqueNo", uniqueNo);
        return super.doGet(url, params, new TypeToken<ResultDto<List<ProductPropertyWithValueResultListDTO>>>() {
        });
    }

    /**
     * 获取设备最新属性
     *
     * @param request
     * @return
     * @throws IOException
     * @throws AppBizRuntimeException
     */
    public ResultDto<List<DevicePropertiesDTO>> postFarmDeviceProperties(FarmDevicePropertiesReqDTO request) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDeviceProperties.post";
        return super.doPost(url, request, new TypeToken<ResultDto<List<DevicePropertiesDTO>>>() {
        });
    }

    /**
     * 田间设备新增
     * */
    public ResultDto<String> farmDeviceCreate(ApiBizFarmDeviceDto farmDeviceDto) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDevice.create";
        return super.doPost(url, farmDeviceDto, new TypeToken<ResultDto<String>>() {
        });
    }

    /**
     * 田间设备修改
     * */
    public ResultDto<String> editDevice(ApiBizFarmDeviceDto farmDeviceDto) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDevice.edit";
        return super.doPost(url, farmDeviceDto, new TypeToken<ResultDto<String>>() {
        });
    }

    /**
     *
     * @param farmDeviceDto
     * @return
     * @throws IOException
     * @throws AppBizRuntimeException
     */
    public ResultDto<String> bindDevice(ApiBizFarmDeviceBindDTO farmDeviceDto) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDevice.bind";
        return super.doPut(url, farmDeviceDto, new TypeToken<ResultDto<String>>() {
        });
    }

    /**
     *
     * @param farmDeviceDto
     * @return
     * @throws IOException
     * @throws AppBizRuntimeException
     */
    public ResultDto unBindDevice(ApiBizFarmDeviceBindDTO farmDeviceDto) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmDevice.unbind";
        return super.doPut(url, farmDeviceDto, new TypeToken<ResultDto<String>>() {
        });
    }

    /*
     * 获取产品列表
     * */
    public ResultDto<List<ApiBizFarmProductDto>> getBizFarmProducts(ApiQueryBizFarmProductDto queryBizFarmProductDto) throws IOException, AppBizRuntimeException {
        String url = "/v1/farmProduct.list";
        return super.doPost(url, queryBizFarmProductDto, new TypeToken<ResultDto<List<ApiBizFarmProductDto>>>() {
        });
    }

    /**
     * 获取设备历史轨迹　for 农机化司
     *
     * @param request
     * @return
     * @throws IOException
     * @throws AppBizRuntimeException
     */
    public NjkResult<NjkPositionResult> queryHistoryPositionsNjk(NjkQueryDevicePositionsReqDto request) throws IOException, AppBizRuntimeException {
        String url = "/v1/njk/device/historyPositions";
        return transDto(doPostNjk(url, request, new TypeToken<NjkResultDTO<NjkPositionResultDTO>>() {
        }));
    }

    NjkResult<NjkPositionResult> transDto(NjkResultDTO<NjkPositionResultDTO> njkPositionResultDTONjkResultDTO) {
        NjkResult<NjkPositionResult> njkResult = new NjkResult<>();
        njkResult.setNStatus(njkPositionResultDTONjkResultDTO.getNStatus());
        njkResult.setNDesc(njkPositionResultDTONjkResultDTO.getNDesc());
        List<NjkPositionResult> njkPositionResults = new ArrayList<>();
        NjkPositionResult njkPositionResult = new NjkPositionResult();
        njkPositionResult.setAccount(njkPositionResultDTONjkResultDTO.getResult().getAccount());
        njkPositionResult.setDeviceId(njkPositionResultDTONjkResultDTO.getResult().getDeviceId());
        njkPositionResult.setFactoryId(njkPositionResultDTONjkResultDTO.getResult().getFactoryId());
        njkPositionResult.setInfoGuid(njkPositionResultDTONjkResultDTO.getResult().getInfoGuid());
        njkPositionResult.setPassword(njkPositionResultDTONjkResultDTO.getResult().getPassword());


        if (njkPositionResultDTONjkResultDTO.getResult() != null
                && njkPositionResultDTONjkResultDTO.getResult().getT() != null) {
            List<NjkPositionResult.T> ts = njkPositionResultDTONjkResultDTO.getResult()
                    .getT().parallelStream().map(tt -> {
                        NjkPositionResult.T t = new NjkPositionResult.T();
                        NjkPositionResult.Geometry geometry = new NjkPositionResult.Geometry();
                        Double[] coordinates = new Double[2];
                        coordinates[0] = tt.getT2();
                        coordinates[1] = tt.getT1();
                        geometry.setCoordinates(coordinates);
                        NjkPositionResult.Property property = new NjkPositionResult.Property();
                        property.setT1(tt.getT2());
                        property.setT2(tt.getT1());
                        property.setT3(tt.getT3());
                        property.setT5(tt.getT5());
                        property.setT6(tt.getT6());
                        property.setT7(tt.getT7());
                        property.setT8(tt.getT8());
                        property.setT10(tt.getT10());
                        property.setT1(tt.getT1());

                        t.setGeometry(geometry);
                        t.setProperties(property);
                        return t;
                    }).collect(Collectors.toList());

            njkPositionResult.setT(ts);
        }

        njkPositionResults.add(njkPositionResult);
        njkResult.setResult(njkPositionResults);
        return njkResult;
    }

    public <T> NjkResultDTO<T> doPostNjk(String url, Object bodyObject, TypeToken<NjkResultDTO<T>> typeToken) throws IOException, AppBizRuntimeException {
        String uri = String.format("%s%s", getServerUrl(), url);
        Map<String, String> headers = signHeaders(bodyObject);
        String payload = bodyObject != null ? gson.toJson(bodyObject) : null;
        String res = WebUtils.doPost(uri, headers, payload, Constants.CHARSET_UTF8, getConnectTimeout(), getReadTimeout());
        if (typeToken == null) {
            NjkResultDTO njkResultDTO = new NjkResultDTO();
            ResultDto resultDto = gson.fromJson(res, ResultDto.class);
            if (resultDto != null) {
                njkResultDTO.setNDesc(resultDto.getMessage());
                njkResultDTO.setNStatus(resultDto.getCode());
            }
            return njkResultDTO;
        } else {
            if (res.contains("code")) {
                NjkResultDTO njkResultDTO = new NjkResultDTO();
                ResultDto genericResultDto = gson.fromJson(res, ResultDto.class);
                if (genericResultDto != null) {
                    njkResultDTO.setNDesc(genericResultDto.getMessage());
                    njkResultDTO.setNStatus(genericResultDto.getCode());
                }
                return njkResultDTO;
            } else {
                return gson.fromJson(res, typeToken.getType());
            }
        }
    }
}
